package dao

import (
	"errors"
	"gorm.io/gorm"
	"kf/models/entity"
	"kf/utils"
	"slices"
	"strconv"
	"strings"
	"time"
)

type SysDeptDao struct {
	DB *gorm.DB
}

func (sysDeptDao *SysDeptDao) ListDeptOptions() []utils.Option[uint64] {
	var deptList = make([]entity.SysDept, 0)
	sysDeptDao.DB.Select("id", "parent_id", "name").
		Where("status=? ", 1).
		Order("sort asc").Find(&deptList)
	var options []utils.Option[uint64]
	if len(deptList) == 0 {
		return options
	}
	var deptIds []uint64
	var parentIds []uint64
	for _, dept := range deptList {
		if !slices.Contains(deptIds, dept.ID) {
			deptIds = append(deptIds, dept.ID)
		}
		if !slices.Contains(parentIds, dept.ParentId) {
			parentIds = append(parentIds, dept.ParentId)
		}
	}
	difference := Difference(parentIds, deptIds)
	for _, rootId := range difference {
		tree := buildDeptTree(rootId, deptList)
		options = append(options, tree...)
	}
	return options
}

func (sysDeptDao *SysDeptDao) GetDepts(queryParams entity.DeptQuery) ([]entity.DeptVO, error) {
	// 查询参数
	keywords := queryParams.Keywords
	status := queryParams.Status

	var deptVoList = make([]entity.DeptVO, 0)

	var sysDepts = make([]entity.SysDept, 0)
	// 查询数据
	tx := sysDeptDao.DB.Model(&entity.SysDept{})
	if status != nil {
		tx.Where("status=? ", *status)
	}
	if keywords != nil {
		tx.Where("name like ? ", "%"+*keywords+"%")
	}
	tx.Order("sort asc").Find(&sysDepts)
	if len(sysDepts) == 0 {
		return deptVoList, nil
	}

	// 获取所有部门ID
	deptSet := make(utils.Set[uint64])
	for _, sysDept := range sysDepts {
		deptSet.Add(sysDept.ID)
	}
	// 获取所有父级ID
	parentSet := make(utils.Set[uint64])
	for _, sysDept := range sysDepts {
		parentSet.Add(sysDept.ParentId)
	}
	// 获取根节点ID（递归的起点），即父节点ID中不包含在部门ID中的节点，注意这里不能拿顶级部门 O 作为根节点，
	//因为部门筛选的时候 O 会被过滤掉
	var rootIds []uint64
	for parentId, _ := range parentSet {
		if !deptSet.Contains(parentId) {
			rootIds = append(rootIds, parentId)
		}
	}
	// 使用递归函数来构建部门树
	var depts []entity.DeptVO
	for _, rootId := range rootIds {
		tree, err := sysDeptDao.BuildDeptTree(rootId, sysDepts)
		if err != nil {
			return nil, err
		}
		depts = append(depts, tree...)
	}
	return depts, nil
}

func (sysDeptDao *SysDeptDao) BuildDeptTree(parentId uint64, deptList []entity.SysDept) ([]entity.DeptVO, error) {
	var routeList []entity.DeptVO
	for _, dept := range deptList {
		if dept.ParentId == parentId {
			deptVo, err := sysDeptDao.toDeptVo(dept)
			if err != nil {
				return nil, err
			}
			children, err := sysDeptDao.BuildDeptTree(dept.ID, deptList)
			if err != nil {
				return nil, err
			}
			if len(children) > 0 {
				deptVo.Children = children
			}
			routeList = append(routeList, deptVo)
		}
	}
	return routeList, nil
}

func (sysDeptDao *SysDeptDao) toDeptVo(dept entity.SysDept) (entity.DeptVO, error) {
	var deptVO entity.DeptVO
	deptVO.ID = dept.ID
	deptVO.ParentId = dept.ParentId
	deptVO.Name = dept.Name
	deptVO.Code = dept.Code
	deptVO.Sort = dept.Sort
	deptVO.Status = dept.Status
	deptVO.CreateTime = dept.CreateTime
	deptVO.UpdateTime = dept.UpdateTime
	return deptVO, nil
}

func (sysDeptDao *SysDeptDao) GetDeptForm(id uint64) (entity.DeptForm, error) {
	var form entity.DeptForm
	var dept entity.SysDept
	result := sysDeptDao.DB.Model(&entity.SysDept{}).Where("id = ?", id).First(&dept)
	if errors.Is(result.Error, gorm.ErrRecordNotFound) {
		return form, errors.New("菜单不存在")
	} else if result.Error != nil {
		return form, result.Error
	}
	form.ID = dept.ID
	form.Name = dept.Name
	form.Code = dept.Code
	form.ParentId = dept.ParentId
	form.Status = dept.Status
	form.Sort = dept.Sort
	return form, nil
}

func (sysDeptDao *SysDeptDao) DeleteDepts(idStr string) (bool, error) {
	if idStr == "" {
		return false, errors.New("至少需要一个参数")
	}
	split := strings.Split(idStr, ",")
	var list []uint64
	for _, val := range split {
		end, _ := strconv.ParseUint(val, 10, 64)
		list = append(list, end)
	}
	for _, id := range list {
		err := sysDeptDao.DB.Delete(&entity.SysDept{}, "id = ?", id).Error
		if err != nil {
			return false, err
		}
	}
	return true, nil
}

func (sysDeptDao *SysDeptDao) UpdateDept(id uint64, form entity.DeptForm) (uint64, error) {
	code := form.Code
	var count int64
	err := sysDeptDao.DB.Model(&entity.SysDept{}).Where("id <> ? and code = ?", id, code).Find(&count).Error
	if err != nil {
		return 0, err
	}
	if count > 0 {
		return 0, errors.New("部门编号已存在")
	}
	path, err := sysDeptDao.generateDeptTreePath(form.ParentId)
	if err != nil {
		return 0, err
	}
	dept := entity.SysDept{
		Model: entity.Model{
			ID:         form.ID,
			UpdateTime: time.Now(),
		},
		Name:     form.Name,
		Code:     form.Code,
		ParentId: form.ParentId,
		TreePath: path,
		Sort:     form.Sort,
		Status:   form.Status,
	}
	err = sysDeptDao.DB.Model(&entity.SysDept{}).Where("id = ? ", id).Updates(&dept).Error
	if err != nil {
		return 0, err
	}
	return dept.ID, nil
}

func (sysDeptDao *SysDeptDao) generateDeptTreePath(parentId uint64) (string, error) {
	treePath := ""
	if ROOT_NODE_ID == parentId {
		treePath = string(parentId)
	} else {
		var dept entity.SysDept
		result := sysDeptDao.DB.Model(&entity.SysDept{}).Where("id = ?", parentId).First(&dept)
		if errors.Is(result.Error, gorm.ErrRecordNotFound) {
			return treePath, errors.New("菜单不存在")
		} else if result.Error != nil {
			return treePath, result.Error
		}
		treePath = dept.TreePath + "," + strconv.FormatUint(dept.ID, 10)
	}
	return treePath, nil
}

func (sysDeptDao *SysDeptDao) SaveDept(form entity.DeptForm) (uint64, error) {
	code := form.Code
	var count int64
	err := sysDeptDao.DB.Model(&entity.SysDept{}).Where("code = ?", code).Find(&count).Error
	if err != nil {
		return 0, err
	}
	if count > 0 {
		return 0, errors.New("部门编号已存在")
	}
	path, err := sysDeptDao.generateDeptTreePath(form.ParentId)
	if err != nil {
		return 0, err
	}
	dept := entity.SysDept{
		Model: entity.Model{
			UpdateTime: time.Now(),
		},
		Name:     form.Name,
		Code:     form.Code,
		ParentId: form.ParentId,
		TreePath: path,
		Sort:     form.Sort,
		Status:   form.Status,
	}
	err = sysDeptDao.DB.Model(&entity.SysDept{}).Create(&dept).Error
	if err != nil {
		return 0, err
	}
	return dept.ID, nil
}

func buildDeptTree(parentId uint64, deptList []entity.SysDept) []utils.Option[uint64] {
	var options []utils.Option[uint64]
	for _, dept := range deptList {
		if dept.ParentId == parentId {
			var option utils.Option[uint64]
			option.Value = dept.ID
			option.Label = dept.Name
			tree := buildDeptTree(dept.ID, deptList)
			if len(tree) > 0 {
				option.Children = tree
			}
			options = append(options, option)
		}
	}
	return options
}

// Difference[T comparable] 返回两个切片s1和s2的差集，即只存在于s1中但不在s2中的元素
func Difference[T comparable](s1, s2 []T) []T {
	var diff []T
	// 创建一个map来快速查找s2中的元素
	s2Map := make(map[T]bool)
	for _, item := range s2 {
		s2Map[item] = true
	}

	// 遍历s1，检查每个元素是否在s2Map中
	for _, item := range s1 {
		if _, exists := s2Map[item]; !exists {
			diff = append(diff, item)
		}
	}

	return diff
}
